package io.cici.worker.core.tracker.task;

import io.cici.common.enums.ExecuteType;
import io.cici.common.enums.TaskInstanceStatus;
import io.cici.common.model.InstanceDetail;
import io.cici.common.request.ServerScheduleJobRequest;
import io.cici.common.request.TaskTrackerReportInstanceStatusRequest;
import io.cici.worker.common.WorkerInfo;
import io.cici.worker.common.utils.TransportUtils;
import io.cici.worker.pojo.model.InstanceInfo;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author Echo009
 * @since 2022/9/19
 */
@Slf4j
public abstract class TaskTracker {

    protected static final int MAX_REPORT_FAILED_THRESHOLD = 5;
    /**
     * 任务实例ID，使用频率过高，从 InstanceInfo 提取出来单独保存一份
     */
    public final long instanceId;
    /**
     * 任务实例信息
     */
    public final InstanceInfo instanceInfo;
    /**
     * 是否结束
     */
    public final AtomicBoolean finished;
    /**
     * TaskTracker创建时间
     */
    protected final long createTime;
    protected final ExecuteType executeType;

    /**
     * worker 运行时元数据
     */
    protected final WorkerInfo workerInfo;
    /**
     * 连续上报多次失败后放弃上报，视为结果不可达，TaskTracker down
     */
    protected int reportFailedCnt = 0;

    protected TaskTracker(ServerScheduleJobRequest req, WorkerInfo workerInfo) {
        this.createTime = System.currentTimeMillis();
        this.workerInfo = workerInfo;
        this.instanceId = req.getInstanceId();

        this.instanceInfo = new InstanceInfo();

        // PowerJob 值拷贝场景不多，引入三方值拷贝类库可能引入类冲突等问题，综合评估手写 ROI 最高
        instanceInfo.setJobId(req.getJobId());
        instanceInfo.setInstanceId(req.getInstanceId());

        instanceInfo.setExecuteType(req.getExecuteType());
        //instanceInfo.setProcessorType(req.getProcessorType());
        instanceInfo.setProcessorInfo(req.getProcessorInfo());
        instanceInfo.setJobParams(req.getJobParams());
        instanceInfo.setInstanceParams(req.getInstanceParams());
        instanceInfo.setThreadConcurrency(req.getThreadConcurrency());
        instanceInfo.setTaskRetryNum(req.getTaskRetryNum());
        //instanceInfo.setLogConfig(req.getLogConfig());
        instanceInfo.setInstanceTimeoutMS(req.getInstanceTimeoutMS());

        // 常用变量初始化
        executeType = ExecuteType.valueOf(req.getExecuteType());

        // 特殊处理超时时间
        if (instanceInfo.getInstanceTimeoutMS() <= 0) {
            instanceInfo.setInstanceTimeoutMS(Integer.MAX_VALUE);
        }

        this.finished = new AtomicBoolean(false);
    }

    public static void reportCreateErrorToServer(ServerScheduleJobRequest req, WorkerInfo workerInfo, Exception e) {
        log.warn("[TaskTracker-{}] create TaskTracker from request({}) failed.", req.getInstanceId(), req, e);
        // 直接发送失败请求
        TaskTrackerReportInstanceStatusRequest req1 = new TaskTrackerReportInstanceStatusRequest();

        req1.setAppId(workerInfo.getAppId());
        req1.setTaskId(req.getJobId());
        req1.setTaskInstanceId(req.getInstanceId());


        req1.setInstanceStatus(TaskInstanceStatus.FAILED.getCode());
        req1.setResult(String.format("init TaskTracker failed, reason: %s", e.toString()));
        req1.setReportTime(System.currentTimeMillis());
        req1.setStartTime(System.currentTimeMillis());
        req1.setSourceAddress(workerInfo.getWorkerAddress());

        TransportUtils.ttReportInstanceStatus(req1, workerInfo.getServerDiscoveryService().getCurrentServerAddress(), workerInfo.getTransporter());
    }

    /**
     * 销毁
     */
    public abstract void destroy();

    /**
     * 停止任务
     */
    public abstract void stopTask();

    /**
     * 查询任务实例的详细运行状态
     *
     * @return 任务实例的详细运行状态
     */
    public abstract InstanceDetail fetchRunningStatus();

    protected void reportFinalStatusThenDestroy(WorkerInfo workerInfo, TaskTrackerReportInstanceStatusRequest reportInstanceStatusReq) {
        String currentServerAddress = workerInfo.getServerDiscoveryService().getCurrentServerAddress();
        // 最终状态需要可靠上报
        boolean serverAccepted = false;
        try {
            serverAccepted = TransportUtils.reliableTtReportInstanceStatus(reportInstanceStatusReq, currentServerAddress, workerInfo.getTransporter());
        } catch (Exception e) {
            log.warn("[TaskTracker-{}] report finished status failed, req={}.", instanceId, reportInstanceStatusReq, e);
        }
        if (!serverAccepted) {
            if (++reportFailedCnt > MAX_REPORT_FAILED_THRESHOLD) {
                log.error("[TaskTracker-{}] try to report finished status(detail={}) lots of times but all failed, it's time to give up, so the process result will be dropped", instanceId, reportInstanceStatusReq);
                destroy();
            }
            return;
        }
        log.info("[TaskTracker-{}] report finished status(detail={}) success", instanceId, reportInstanceStatusReq);
        destroy();
    }
}
